package infra

import (
	log "github.com/sirupsen/logrus"
	"github.com/tietang/props/kvs"
	"reflect"
	"sort"
)

const (
	KeyProps = "_conf" // 基础资源上下文Map的key常量值
)

// 基础资源上下文结构体，用来在服务资源初始化、安装、启动和停止的生命周期中进行变量和对象的传递
type StarterContext map[string]interface{}

// 返回资源配置实例
func (s StarterContext) Props() kvs.ConfigSource {
	p := s[KeyProps]
	if p == nil {
		panic("配置还没被初始化")
	}
	return p.(kvs.ConfigSource) // 将基础资源上下文Map的值：interface类型向下转型为kvs.ConfigSource
}

func (s StarterContext) SetProps(conf kvs.ConfigSource) {
	s[KeyProps] = conf
}

/*
资源服务启动器接口：每个应用少不了依赖其他资源服务，如：数据库、缓存、消息中间件等等。
启动器实现类，不需要实现所有方法，只需要实现对应的阶段方法即可，可以嵌入@BaseStarter。
通过实现资源启动器接口和资源启动注册器，可以友好地管理这些资源的初始化、安装、启动和停止。
Starter对象注册器作用：将所有需要在系统启动时需要实例化和运行的逻辑，都可以实现在此接口里。
注意只有Start方法才能被阻塞，如果是阻塞Start()，同时StartBlocking()要返回true
*/
type Starter interface {
	Init(StarterContext)  // 1.资源初始化，通常把一些准备资源放在这里运行
	Setup(StarterContext) // 2.资源的安装，所有启动需要的具备条件，使得资源达到可以启动的就备状态
	Start(StarterContext) // 3.启动资源，达到可以使用的状态
	// 4.启动器开始启动服务时是否可阻塞。
	// 如果存在多个阻塞启动器时，只有最后一个阻塞，而之前的会通过goroutine来异步启动。所以需要规划好启动器注册顺序
	StartBlocking() bool
	// 5.资源停止：
	// 通常在启动时遇到异常时或者启用远程管理时，用于释放资源和终止资源的使用。
	// 通常要优雅的释放，等待正在进行的任务继续，但不再接受新的任务
	Stop(StarterContext)

	PriorityGroup() PriorityGroup
	Priority() int
}

// 资源服务启动注册器，全局只有一个而不需在外部构造
type starterRegister struct {
	// 所有资源服务都会注册到此启动注册器里，启动注册器把所有的资源服务都存储在切片里，所以在初始和注册资源服务启动时，
	// 就按照资源服务启动切片内的元素顺序来逐一初始化和注册每一个资源启动器
	nonBlockingStarters []Starter
	blockingStarters    []Starter
}

//返回所有的资源服务启动器
func (r *starterRegister) AllStarters() []Starter {
	starters := make([]Starter, 0)
	starters = append(starters, r.nonBlockingStarters...)
	starters = append(starters, r.blockingStarters...)
	return starters
}

//注册资源服务启动器
func (r *starterRegister) Register(starter Starter) {
	if starter.StartBlocking() {
		r.blockingStarters = append(r.blockingStarters, starter)
	} else {
		r.nonBlockingStarters = append(r.nonBlockingStarters, starter)
	}

	typ := reflect.TypeOf(starter)
	log.Infof("Register starter: %s", typ.String())
}

var StarterRegister *starterRegister = &starterRegister{}

type Starters []Starter

func (s Starters) Len() int      { return len(s) }
func (s Starters) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s Starters) Less(i, j int) bool {
	return s[i].PriorityGroup() > s[j].PriorityGroup() && s[i].Priority() > s[j].Priority()
}

// 注册资源服务启动器到注册启动器切片里
func Register(s Starter) {
	StarterRegister.Register(s)
}

// 对注册启动器切片内的元素进行排序
func SortStarters() {
	sort.Sort(Starters(StarterRegister.AllStarters()))
}

// 获取所有注册的资源服务启动器
func GetStarters() []Starter {
	return StarterRegister.AllStarters()
}

type PriorityGroup int

const (
	SystemGroup         PriorityGroup = 30
	BasicResourcesGroup PriorityGroup = 20
	AppGroup            PriorityGroup = 10

	INT_MAX          = int(^uint(0) >> 1)
	DEFAULT_PRIORITY = 10000
)

// 启动管理器接口，供所有应用启动器实现（非必须实现全部方法）
type BaseStarter struct {
}

// 初始化资源上下文Map
func (s *BaseStarter) Init(ctx StarterContext) {}

// 安装/注册资源上下文Map
func (s *BaseStarter) Setup(ctx StarterContext) {}

// 启动资源上下文Map
func (s *BaseStarter) Start(ctx StarterContext) {}

// 停止资源上下文Map
func (s *BaseStarter) Stop(ctx StarterContext) {}

// 是否以阻塞方式启动启动器-true:是；fale:否
func (s *BaseStarter) StartBlocking() bool { return false }

func (s *BaseStarter) PriorityGroup() PriorityGroup { return BasicResourcesGroup }

func (s *BaseStarter) Priority() int { return DEFAULT_PRIORITY }
